/*
 * Semaforo.cpp
 *
 *  Created on: Oct 17, 2013
 *      Author: gonprieto
 */

#include "Semaforo.h"
#include <errno.h>
#include <string>

Semaforo::Semaforo(const char* nombre, int cantidadSemaforos) {

	this->cantidadSemaforos = cantidadSemaforos;
	key_t clave = ftok(nombre, 'a');
	this->id = semget(clave, cantidadSemaforos, 00770 | IPC_CREAT | IPC_EXCL);

	if ((this->id == -1) && (errno == EEXIST)) {
		//ya existe el conjunto, no inicializo
		this->id = semget(clave, cantidadSemaforos, 00770 | IPC_CREAT);
		return;
	}
}

Semaforo::~Semaforo() {
}


int Semaforo::inicializar(int valoresIniciales[]) {
	for (int i = 0; i < this->cantidadSemaforos; i++){
		if ( inicializar(i, valoresIniciales[i]) == -1){
			return -1;
		}
	}
	return 0;
}

int Semaforo::inicializar(int posSem, int valor) {
	union semnum {
		int val;
		struct semid_ds* buf;
		ushort* array;
	};
	semnum init;
	init.val = valor;
	int resultado = semctl(this->id, posSem, SETVAL, init);
	return resultado;
}

int Semaforo::getValor(int numSem) {
	int resultado = semctl(this->id, numSem, GETVAL);

	return resultado;
}

int Semaforo::p(int numSem) {
	struct sembuf operacion;
	operacion.sem_num = numSem;	// numero de semaforo
	operacion.sem_op = -1;	// restar 1 al semaforo
	operacion.sem_flg = 0;
	int resultado = semop(this->id, &operacion, 1);

	if(resultado == -1){
		Logger::instancia() << "Semaforo::p - ERROR - no pude cambiar el resultado de id :"<< this->id << " Error:" << strerror(errno) <<eol;
		perror("mknod");
	}

	Logger::instancia() << "Semaforo::p - Restando 1 al semaforo id: " << this->id
			<< ", Resultado: " << resultado << ", valor semaforo: "
			<< getValor(numSem) << eol;
	return resultado;
}

int Semaforo::v(int numSem) {
	struct sembuf operacion;
	operacion.sem_num = numSem;	// numero de semaforo
	operacion.sem_op = 1;	// sumar 1 al semaforo
	operacion.sem_flg = 0;
	int resultado = semop(this->id, &operacion, 1);

	if(resultado == -1){
		Logger::instancia() << "Semaforo::v - ERROR - no pude cambiar el resultado de id :"<< this->id << " Error:" << strerror(errno) <<eol;
		perror("mknod");
	}

	Logger::instancia() << "Semaforo::v - Sumando 1 al semaforo id: " << this->id
			<< ", Resultado: " << resultado << ", valor semaforo: "
			<< getValor(numSem) << eol;
	return resultado;
}

void Semaforo::eliminar() {
	// elimina el conjunto, semnum es ignorado
	semctl(this->id, 0, IPC_RMID);
}
